﻿//using WcfRestSql;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Web.Script.Serialization;
using System.Xml.Serialization;
using System.Configuration;
using System.Web;
using HRM.Common;


    public static class RestSqlClientUtilities // extension methods for http service client
    {
        //Handle sự kiện khi Execute lỗi sp
        private static void HandleErrorExecute(DataSet ds)
        {
            if (ds != null && ds.Tables.Contains("ERROR"))
            {
//                throw new Exception(Globals.Object_GetValue<string>(ds.Tables["ERROR"].Rows[0][0]));
                FormGlobals.Message_Error(new Exception(Globals.Object_GetValue<string>(ds.Tables["ERROR"].Rows[0][0])));
            }
        }

        public static int ExecuteNonquery(this wcf_rest_sqlcommand sqlcmd)
        {
            sqlcmd.executetype = "nonquery";
            DataSet ds = (DataSet)runWcfRestSql(sqlcmd, "runSqlDs");
            HandleErrorExecute(ds);
            return Globals.Object_GetValue<int>(ds.Tables[0].Rows[0][0]);
        }

        public static object ExecuteScalar(this wcf_rest_sqlcommand sqlcmd)
        {
            sqlcmd.executetype = "scaler";
            DataSet ds = (DataSet)runWcfRestSql(sqlcmd, "runSqlDs");
            HandleErrorExecute(ds);
            return ds.Tables[0].Rows[0][0];
        }

        public static DataSet ExecuteDataSet(this wcf_rest_sqlcommand sqlcmd)
        {
            sqlcmd.executetype = "";
            DataSet ds= (DataSet)runWcfRestSql(sqlcmd, "runSqlDs");
            HandleErrorExecute(ds);
            return ds;
        }

        public static DataTable ExecuteDataTable(this wcf_rest_sqlcommand sqlcmd)
        {
            sqlcmd.executetype = "";
            DataSet ds = ((DataSet)runWcfRestSql(sqlcmd, "runSqlDs"));
            HandleErrorExecute(ds);
            return ds.Tables[0];
        }

        public static string ExecuteXml(this wcf_rest_sqlcommand sqlcmd)
        {
            sqlcmd.executetype = "xml";
            return Globals.Object_GetValue<string>(runWcfRestSql(sqlcmd, "runSqlDs"));
        }

        public static string ExecuteJson(this wcf_rest_sqlcommand sqlcmd)
        {
            sqlcmd.executetype = "json";
            return Globals.Object_GetValue<string>(runWcfRestSql(sqlcmd, "runSqlDs"));
        }

        private static object runWcfRestSql(this wcf_rest_sqlcommand sqlcmd, string methodToRun)
        {
            // extension method for wcf_rest_sqlcommand creates http request and returns response
            // "methodToRun" is name of method called in IWcfRestSql.  Possible values:
            //      "runSqlDS" (returns DataSet)
            //      "runSqlXml" (returns xml as string)
            //      "RunSqlJson" (returns Json as string)
            //
            byte[] data; // payload
            object returnValue = new object(); // might be a dataset or a string
            // set up uri for service call -- methodToRun can be "runSqlDS", "runSqlJson", or "runSqlXml" 
            string strRemoteConnect = System.Configuration.ConfigurationManager.AppSettings["RemoteConnect"];
            
            
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(
                strRemoteConnect + "/WcfRestSql.svc/" + methodToRun);
            req.Method = "POST";
            //if (methodToRun.ToLower().Contains("json")) // need json payload
            if (sqlcmd.jsonformat)
            {
                req.ContentType = @"application/json; charset=utf-8";
                data = sqlcmd.toJsonPayload(); // extension method to generate json payload in byte[] data
            }
            else // xml payload
            {
                req.ContentType = @"application/xml; charset=utf-8";
                data = sqlcmd.toXmlPayload();  // extension method to generate xml payload in byte[] data
            }
            req.ContentLength = data.Length;
            //req.Headers.Add("Authenticate",Globals.String_Encrypt("hrm;ise","1987"));
            Stream requestStream = req.GetRequestStream();
            requestStream.Write(data, 0, data.Length); // write payload to http request
            HttpWebResponse response = (HttpWebResponse)req.GetResponse();
            if (response.StatusCode == HttpStatusCode.OK) // process result
            {
                using (StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
                {   // check if we're returning string (xml / json) or dataset
                    if (methodToRun.ToLower().Contains("json") || methodToRun.ToLower().Contains("xml"))
                        returnValue = sr.ReadToEnd(); // returns json or xml formatted results
                    else // DataSet (one or more DataTables) 
                    {
                        DataSet ds = new DataSet(); // get dataset directly from service call
                        StringReader xmlSR = new StringReader(sr.ReadToEnd());
                        ds.ReadXml(xmlSR, XmlReadMode.Auto);
                        returnValue = ds; // return dataset to caller
                    }
                }
            }
            else // service not run, check error returned
            {
                string sError = string.Format("ERROR: Status Code: {0}, Status Description: {1}",
                    response.StatusCode, response.StatusDescription);

                //throw new Exception(sError);
                return sError;
            }
            return returnValue;
        }
        public static byte[] toJsonPayload(this object obj) // object extension converts obj to json payload byte[] 
        {
            return (Encoding.UTF8.GetBytes(new JavaScriptSerializer().Serialize(obj)));

            //return (Encoding.Unicode.GetBytes(new JavaScriptSerializer().Serialize(obj)));
        }

        public static byte[] toXmlPayload(this object obj)  // object extension converts obj to xml payload byte[] 
        {
            //Type objType = obj.GetType();
            //string objName = objType.Name;
            //System.Reflection.PropertyInfo[] propInfo = objType.GetProperties();
            //var orderedProperties = from p in propInfo orderby p.Name select p;

            //MemoryStream mStream = new MemoryStream();
            //XmlTextWriter xmlWriter = new XmlTextWriter(mStream, Encoding.UTF8);
            //xmlWriter.WriteStartDocument();
            //xmlWriter.WriteStartElement(objName); // name of payload, i.e. "wcf_rest_sqlcommand"

            //foreach (PropertyInfo info in orderedProperties) // for each property in obj
            //{
            //    xmlWriter.WriteStartElement(info.Name); // property name


            //    //if (!info.PropertyType.Equals(typeof(List<Object>)))
            //        xmlWriter.WriteString(info.GetValue(obj, null).ToString()); // property value
            //    //else
            //    //{
            //     //   WriteXMLNode(xmlWriter, info.GetValue(obj, null));
            //    //}
            //    xmlWriter.WriteEndElement();
            //}
            //xmlWriter.WriteEndElement();
            //xmlWriter.WriteEndDocument();
            //string test = xmlWriter.ToString();
            //xmlWriter.Flush();
            //return mStream.ToArray(); // return xml representation of obj in byte[] array



            return GetBytes(CreateXML(obj));


        }

        private static void WriteXMLNode(XmlTextWriter xmlWriter, Object obj)
        {
            Type objType = obj.GetType();
            string objName = objType.Name;
            System.Reflection.PropertyInfo[] propInfo = objType.GetProperties();
            var orderedProperties = from p in propInfo orderby p.Name select p;

            foreach (PropertyInfo info in orderedProperties) // for each property in obj
            {
                xmlWriter.WriteStartElement(info.Name); // property name
                if (!info.PropertyType.Equals(typeof(List<Object>)))
                    xmlWriter.WriteString(info.GetValue(obj, null).ToString()); // property value
                else
                {
                    WriteXMLNode(xmlWriter, info.GetValue(obj, null));
                }
                xmlWriter.WriteEndElement();
            }
        }

        public static string CreateXML(Object YourClassObject)
        {
            XmlDocument xmlDoc = new XmlDocument();   //Represents an XML document, 
            // Initializes a new instance of the XmlDocument class.          
            XmlSerializer xmlSerializer = new XmlSerializer(YourClassObject.GetType());

            // Creates a stream whose backing store is memory. 
            using (MemoryStream xmlStream = new MemoryStream())
            {
                xmlSerializer.Serialize(xmlStream, YourClassObject);
                xmlStream.Position = 0;

                //Loads the XML document from the specified string.
                xmlDoc.Load(xmlStream);
                return xmlDoc.InnerXml;
            }
        }

        static byte[] GetBytes(string str)
        {
            byte[] bytes = new byte[str.Length * sizeof(char)];
            System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
            return bytes;
        }

        static string GetString(byte[] bytes)
        {
            char[] chars = new char[bytes.Length / sizeof(char)];
            System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
            return new string(chars);
        }

        public static List<T> toCollection<T>(this DataTable dt) // DataTable extension converts DataTable to <T>
        {
            List<T> lst = new System.Collections.Generic.List<T>();
            Type tClass = typeof(T);
            PropertyInfo[] pClass = tClass.GetProperties();
            List<DataColumn> dc = dt.Columns.Cast<DataColumn>().ToList();
            T cn;
            foreach (DataRow item in dt.Rows)
            {
                cn = (T)Activator.CreateInstance(tClass);
                foreach (PropertyInfo pInfo in pClass)
                {
                    try
                    {
                        DataColumn d = dc.Find(c => c.ColumnName == pInfo.Name);
                        if (d != null)
                            pInfo.SetValue(cn, item[pInfo.Name], null);
                    }
                    catch
                    {
                    }
                }
                lst.Add(cn);
            }
            return lst;
        }
        public static void showDataSet(this DataSet ds)  // DataSet extension to dump data tables to console for testing
        {
            int tables = ds.Tables.Count;
            if (tables < 1)
            {
                Console.Write("No values returned from Stored Procedure.");
                return;
            }
            for (int t = 0; t < tables; t++)
            {
                int rows = ds.Tables[t].Rows.Count;
                if (rows == 0)
                {
                    Console.WriteLine("\nNo Records Returned in DataSet Table: [" + t + "]\n");
                }
                else
                {
                    int cols = ds.Tables[t].Rows[0].ItemArray.Count();
                    for (int n = 0; n < cols; n++)
                    {
                        Console.Write(ds.Tables[t].Columns[n].ColumnName + "\t");
                    }
                    if (rows > 0 && cols > 0) // make sure we have fields in table
                    {
                        Console.WriteLine("");
                        for (int r = 0; r < rows; r++)
                        {
                            // Console.Write("Row: " + r.ToString() + ":\t");
                            for (int c = 0; c < cols; c++)
                            {
                                Console.Write("  " + ds.Tables[t].Rows[r].ItemArray[c].ToString() + "\t");
                            }
                            Console.Write("\n");
                        }
                    }
                }
            }
        }
    }
